package com.atcc.test.domain;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.multipart.MultipartFile;

import com.alibaba.fastjson.JSON;
import com.atcc.test.pojo.RequestErrorInfo;
import com.atcc.test.pojo.RequestInfo;

@Component
@Aspect
public class RequestLogAspect {
	
	private final Logger logger = LoggerFactory.getLogger(RequestLogAspect.class);
	
	@Pointcut("execution(* com.atcc.test.controller..*(..))")
	public void requestServer() {
	}
	
	@Around("requestServer()")
	public Object doAround(ProceedingJoinPoint ProceedingjoinPoint) throws Throwable {
		long StartTime = System.currentTimeMillis();
		ServletRequestAttributes attribute = 
				(ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
		HttpServletRequest request = attribute.getRequest();
		logger.info("启动目标方法执行,当前时间为:" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
		Object result = ProceedingjoinPoint.proceed();
		RequestInfo requestInfo = new RequestInfo();
		requestInfo.setIp(request.getRemoteAddr());
		requestInfo.setHttpMethod(request.getMethod());
		requestInfo.setUrl(request.getRequestURI().toString());
		requestInfo.setResult(result);
		requestInfo.setRequestParam(getRequestParamsByProceedingJoinPoint(ProceedingjoinPoint));
		requestInfo.setClassMethod(String.format("%s.%s", ProceedingjoinPoint.getSignature().getDeclaringTypeName(),
				ProceedingjoinPoint.getSignature().getName()));
		requestInfo.setTimeCost(System.currentTimeMillis()-StartTime);
		logger.info("Request Info      : {}", JSON.toJSONString(requestInfo));
		return result;
	}
	
    @AfterThrowing(pointcut = "requestServer()", throwing = "e")
    public void doAfterThrow(JoinPoint joinPoint, RuntimeException e) {
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        RequestErrorInfo requestErrorInfo = new RequestErrorInfo();
        requestErrorInfo.setIp(request.getRemoteAddr());
        requestErrorInfo.setUrl(request.getRequestURL().toString());
        requestErrorInfo.setHttpMethod(request.getMethod());
        requestErrorInfo.setClassMethod(String.format("%s.%s", joinPoint.getSignature().getDeclaringTypeName(),
                joinPoint.getSignature().getName()));
        requestErrorInfo.setRequestParams(getRequestParamsByJoinPoint(joinPoint));
        requestErrorInfo.setException(e);
        logger.info("Error Request Info      : {}", JSON.toJSONString(requestErrorInfo));
    }

	private Map<String,Object> getRequestParamsByProceedingJoinPoint(ProceedingJoinPoint ProceedingjoinPoint) {
		
		//参数名
		String[] paramNames = ((MethodSignature)ProceedingjoinPoint.getSignature()).getParameterNames();
		//参数值
		Object[] paramValues = ProceedingjoinPoint.getArgs();
		
		return buildRequestParam(paramNames,paramValues);
	}
	
	private Map<String,Object> getRequestParamsByJoinPoint(JoinPoint joinPoint) {
			
			//参数名
			String[] paramNames = ((MethodSignature)joinPoint.getSignature()).getParameterNames();
			//参数值
			Object[] paramValues = joinPoint.getArgs();
			
			return buildRequestParam(paramNames,paramValues);
		}

	private Map<String, Object> buildRequestParam(String[] paramNames, Object[] paramValues) {
		Map<String,Object> requestParams = new HashMap<>();
		for (int i = 0; i < paramNames.length; i++) {
            Object value = paramValues[i];
            if (value instanceof MultipartFile) {
                MultipartFile file = (MultipartFile) value;
                value = file.getOriginalFilename();  //获取文件名
            }
            requestParams.put(paramNames[i], value);
        }

        return requestParams;
	}
	

}
